package com.demo.modules.job.task;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.demo.modules.stock.entity.StockDayEntity;
import com.demo.modules.stock.entity.StockInfoEntity;
import com.demo.modules.stock.entity.StockUpStatisticsEntity;
import com.demo.modules.stock.service.StockDayService;
import com.demo.modules.stock.service.StockInfoService;
import com.demo.modules.stock.service.StockUpStatisticsService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.sql.Timestamp;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * 定时任务
 * stockStatisticsTask bean的名称
 */
@Component("stockStatisticsTask")
public class stockStatisticsTask implements ITask {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    StockInfoService stockInfoService;

    @Resource
    StockDayService stockDayService;

    @Resource
    StockUpStatisticsService stockUpStatisticsService;

    /**
     * @param params 参数，多参数用逗号分开
     */
    @Override
    public void run(String params) {
        logger.debug("TestTask定时任务正在执行，参数为：{}", params);
        if (StringUtils.isEmpty(params)) return;
        String[] p = params.split(",");
        if ("1".equals(p[0])) {
            stockRiseRateWithYesterday();
        }
        if ("2".equals(p[0])) {
            stockStatisticsRise(p[1]);
        }
        if ("3".equals(p[0])) {
            //5日均线等价格生成
            if (p.length > 1) {
                stockMaPrice("history");
            } else {
                stockMaPrice("recent");
            }
        }

    }

    /**
     * 5日均线等价格生成
     */
    private void stockMaPrice(String type) {
        logger.debug("5日均线等价格生成");
        List<StockInfoEntity> stockList = stockInfoService.list();

        for (StockInfoEntity e : stockList) {
            List<StockDayEntity> closePriceList;
            if ("history".equals(type)) {
                //查询股票的所有历史收盘价
                closePriceList = stockDayService.list(new QueryWrapper<StockDayEntity>().select("ID,DAY_DATE,close_price")
                        .eq("STOCK_CODE", e.getStockCode())
                        .orderByAsc("DAY_DATE"));
            } else {
                //仅查询最近60天的收盘价
                closePriceList = stockDayService.list(new QueryWrapper<StockDayEntity>().select("ID,DAY_DATE,close_price")
                        .eq("STOCK_CODE", e.getStockCode())
                        .orderByDesc("DAY_DATE").last("limit 60"));
                Collections.reverse(closePriceList);
            }

            for (int i = 0; i < closePriceList.size(); i++) {
                if (i >= 4) {
                    //5日均线
                    double ma5 = 0;
                    for (int j = i; j >= i - 4; j--) {
                        ma5 += closePriceList.get(j).getClosePrice();
                    }
                    closePriceList.get(i).setMa5(NumberUtil.round(ma5 / 5, 2).doubleValue());
                }
                if (i >= 9) {
                    //10日均线
                    double ma10 = 0;
                    for (int j = i; j >= i - 9; j--) {
                        ma10 += closePriceList.get(j).getClosePrice();
                    }
                    closePriceList.get(i).setMa10(NumberUtil.round(ma10 / 10, 2).doubleValue());
                }
                if (i >= 19) {
                    //20日均线
                    double ma20 = 0;
                    for (int j = i; j >= i - 19; j--) {
                        ma20 += closePriceList.get(j).getClosePrice();
                    }
                    closePriceList.get(i).setMa20(NumberUtil.round(ma20 / 20, 2).doubleValue());
                }
                if (i >= 30) {
                    //30日均线
                    double ma30 = 0;
                    for (int j = i; j >= i - 29; j--) {
                        ma30 += closePriceList.get(j).getClosePrice();
                    }
                    closePriceList.get(i).setMa30(NumberUtil.round(ma30 / 30, 2).doubleValue());
                }
            }
            stockDayService.updateBatchById(closePriceList);
        }
    }

    private void stockRiseRateWithYesterday() {
        logger.debug("股票和昨天的股价比率");
        List<StockInfoEntity> stockInfoEntityList = stockInfoService.list();
        StockInfoEntity updateStock;
        List<StockDayEntity> dayList;
        for (StockInfoEntity e : stockInfoEntityList) {
            updateStock = new StockInfoEntity();
            //查询股票的最新两日收盘价
            dayList = stockDayService.list(new QueryWrapper<StockDayEntity>().select("DAY_DATE,close_price")
                    .eq("STOCK_CODE", e.getStockCode())
                    .orderByDesc("DAY_DATE").last("limit 2"));
            if (dayList.size() == 2) {
                updateStock.setId(e.getId());
                updateStock.setCurrentPrice(dayList.get(0).getClosePrice());
                updateStock.setPriceLimit(NumberUtil.round((dayList.get(0).getClosePrice() - dayList.get(1).getClosePrice()) / dayList.get(1).getClosePrice(), 4).doubleValue());
                updateStock.setUpdateTime(new Timestamp(DateUtil.date().getTime()));
                stockInfoService.updateById(updateStock);
            }
        }
    }

    /**
     * 股票在n天内的涨跌次数
     *
     * @param statisticsDays
     */
    private void stockStatisticsRise(String statisticsDays) {

        logger.debug("股票在{}天内的涨跌次数", statisticsDays);

        //删除股票的涨跌统计信息
        stockUpStatisticsService.remove(new QueryWrapper<StockUpStatisticsEntity>().isNotNull("STOCK_CODE"));

        //获取建设银行最近几个交易日的开始日期和结束日期作为所有股票查询的开始和截止日期
        List<StockDayEntity> tmp = stockDayService.list(new QueryWrapper<StockDayEntity>()
                .eq("STOCK_CODE", "601939").orderByDesc("DAY_DATE").last("limit " + statisticsDays));
        Date startDate = tmp.get(tmp.size() - 1).getDayDate();
        Date endDate = tmp.get(0).getDayDate();

        List<StockDayEntity> resentDays;
        List<StockInfoEntity> stockInfoEntityList = stockInfoService.list();
        for (StockInfoEntity e : stockInfoEntityList) {
            resentDays = stockDayService.list(new QueryWrapper<StockDayEntity>()
                    .select("DAY_DATE,open_price,close_price,highest,lowest").eq("STOCK_CODE", e.getStockCode())
                    .between("DAY_DATE", startDate, endDate).orderByAsc("DAY_DATE"));

            StockUpStatisticsEntity statistics = setStockUpStatisticsService(resentDays, Integer.parseInt(statisticsDays), e.getStockCode(), e.getStockName());

            stockUpStatisticsService.save(statistics);
        }
    }

    /**
     * 统计股票一段时间内的涨跌次数
     */
    private StockUpStatisticsEntity setStockUpStatisticsService(List<StockDayEntity> list, int statisticsDays, String stockCode, String stockName) {
        StockUpStatisticsEntity statistics = new StockUpStatisticsEntity();
        int riseDays = 0;                   //上涨次数
        int fallDays = 0;                   //下跌次数
        int riseStopDays = 0;               //涨停天数
        int continueRiseStopDays = 0;       //连续涨停天数
        int fallStopDays = 0;               //跌停天数
        int continueFallStopDays = 0;       //连续跌停天数
        int continueRiseDays = 0;           //连续上涨次数
        int continueFallDays = 0;           //连续下跌次数
        boolean continueRise = true;        //连续上涨标志
        boolean continueFall = true;        //连续下跌标志
        double continueRiseRate = 0;        //
        double continueFallRate = 0;        //
        for (int i = list.size() - 1; i > 1; i--) {
            if (list.get(i).getClosePrice() >= list.get(i - 1).getClosePrice()) {
                //上涨
                riseDays++;

                if ((list.get(i).getClosePrice() - list.get(i - 1).getClosePrice()) / list.get(i - 1).getClosePrice() >= 0.099) {
                    //涨停
                    riseStopDays++;
                }

                continueFall = false; //比昨天的股票高则不存在连续下跌
                if (continueRise) {
                    //连续上涨
                    continueRiseDays++;
                    continueFallRate = (list.get(list.size() - 1).getClosePrice() - list.get(i).getClosePrice()) / list.get(i).getClosePrice();
                    if ((list.get(i).getClosePrice() - list.get(i - 1).getClosePrice()) / list.get(i - 1).getClosePrice() >= 0.099) {
                        //连续上涨期间涨停次数
                        continueRiseStopDays++;
                    }
                }
            } else {
                //下跌
                fallDays++;

                if ((list.get(i).getClosePrice() - list.get(i - 1).getClosePrice()) / list.get(i - 1).getClosePrice() <= -0.099) {
                    //跌停
                    fallStopDays++;
                }

                continueRise = false; //比昨天的股票低则不存在连续上涨
                //连续下跌
                if (continueFall) {
                    continueFallDays++;
                    if ((list.get(i).getClosePrice() - list.get(i - 1).getClosePrice()) / list.get(i - 1).getClosePrice() <= -0.099) {
                        //连续下跌期间跌停次数
                        continueFallStopDays++;
                    }
                }
            }
        }
        statistics.setRiseDays(riseDays);
        statistics.setFallDays(fallDays);
        statistics.setRiseStopDays(riseStopDays);
        statistics.setFallStopDays(fallStopDays);

        statistics.setContinueRiseDays(continueRiseDays);
        statistics.setContinueRiseRate(continueRiseRate);
        statistics.setContinueFallDays(continueFallDays);
        statistics.setContinueFallRate(continueFallRate);

        statistics.setContinueFallStopDays(continueFallStopDays);
        statistics.setContinueRiseStopDays(continueRiseStopDays);

        statistics.setStatisticsDays(statisticsDays);
        statistics.setStockCode(stockCode);
        statistics.setStockName(stockName);
        statistics.setCreateTime(new Timestamp(DateUtil.date().getTime()));
        //设置k线名称
        statistics.setKLineName(getKLineName(list));
        return statistics;

    }

    private String getKLineName(List<StockDayEntity> list) {
        if (list.size() > 1) {
            Double openPrice = list.get(list.size() - 1).getOpenPrice();
            Double closePrice = list.get(list.size() - 1).getClosePrice();
            Double lowest = list.get(list.size() - 1).getLowest();
            Double highest = list.get(list.size() - 1).getHighest();
            /*System.out.println(list.get(list.size() - 1).getStockCode());
            System.out.println(openPrice + " " + closePrice + " " + lowest + " " + highest);*/
            if (closePrice.equals(highest) && openPrice.equals(lowest)) return "光头光脚阳线";
            if (closePrice.equals(highest)) return "光头阳线";
            if (openPrice.equals(lowest)) return "光脚阳线";
        }
        return "";
    }
}
